<template>
  <div class="td-box" ref="can"></div>
</template>
<script setup>
import {
  computed,
  onBeforeUnmount,
  onMounted,
  reactive,
  ref,
  watch,
} from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import editStore from "@/store/editStore";
import { getAssetsFile } from "@/utils/index.js";
import { debounce } from "@/utils";

let props = defineProps({
  from: {
    type: String,
    default: "",
  },
  storeJson: {
    type: Object,
    default: () => {},
  },
});

const store = computed(() => {
  return props.from == "home" ? props.storeJson : editStore();
});

let frameId = null; //旋转动作id
let can = ref();
let render = null;
let controls = null;
let camera = null;
let mesh = null;
let reel = null;
let currentReel = null;

let scene = new THREE.Scene();
let loader = new THREE.TextureLoader();
// scene.background = new THREE.Color("rgb(214, 220, 242)");

let AmbientLight = new THREE.AmbientLight("#fff", 1);
scene.add(AmbientLight);

function init() {
  reel = store.value.reelConfig;
  currentReel = reel.reelList[store.value.reelIndex];

  let Cylinder = new THREE.CylinderGeometry(
    reel.reelDiameter / 2,
    reel.reelDiameter / 2,
    reel.reelThickness,
    60
  );
  Cylinder.rotateY(Math.PI / 2);
  let reelFrontImg = reel.frontImg ? reel.frontImg : getAssetsFile("reel-x");
  let ftexture = loader.load(reelFrontImg, (texture) => {
    render.render(scene, camera);
  });

  let Material1 = new THREE.MeshBasicMaterial({
    transparent: true,
    map: ftexture,
    color: currentReel.reelColor,
  });

  let reelOppoImg = reel.oppositeImg
    ? reel.oppositeImg
    : getAssetsFile("reel-opp-x");
  let Material2 = new THREE.MeshBasicMaterial({
    transparent: true,
    map: loader.load(reelOppoImg),
    color: currentReel.reelColor,
  });
  let Material3 = new THREE.MeshBasicMaterial({
    color: "#444",
  });
  let maters = [Material3, Material1, Material2];

  mesh = new THREE.Mesh(Cylinder, maters);
  mesh.position.set(0, 0, 0);
  // mesh.rotation.set(0, Math.PI / 2, 0);

  scene.add(mesh);

  currentReel.frontComponentList.forEach((item) => {
    if (item.type == "Labels" || item.type == "Humidity") {
      createPlaneGeometry(item, "front");
    } else if (item.type == "Desiccant") {
      createBoxGeometry(item, "front");
    }
  });
  currentReel.oppositeComponentList.forEach((item) => {
    if (item.type == "Labels" || item.type == "Humidity") {
      createPlaneGeometry(item, "opposite");
    } else if (item.type == "Desiccant") {
      createBoxGeometry(item, "opposite");
    }
  });
}

// let axes = new THREE.AxesHelper(500);
// scene.add(axes);

function createPlaneGeometry(item, type) {
  let label = new THREE.PlaneGeometry(item.length, item.width);
  let texture = loader.load(item.picName, () => {
    render.render(scene, camera);
  });
  let material = new THREE.MeshBasicMaterial({
    map: texture,
    side: THREE.DoubleSide,
    color: "#fff",
  });
  let lmesh = new THREE.Mesh(label, material);
  let yIndex = reel.reelThickness / 2 + 2;
  yIndex = type == "front" ? yIndex : yIndex * -1;
  lmesh.position.set(item.x + item.length / 2, yIndex, item.y + item.width / 2);
  lmesh.rotation.set(-Math.PI / 2, 0, -(item.angle / 180) * Math.PI);
  mesh.add(lmesh);
  if (item.qaStamp) {
    createCircleGeometry(item, type, lmesh);
  }
}

function createBoxGeometry(item, type) {
  let desci = new THREE.BoxGeometry(item.length, item.width, 8);
  let dtexture = loader.load(item.picName, () => {
    render.render(scene, camera);
  });
  let material = new THREE.MeshBasicMaterial({
    map: dtexture,
    side: THREE.DoubleSide,
    opacity: 0.3,
  });
  let material2 = new THREE.MeshBasicMaterial({
    color: "#eee",
    side: THREE.DoubleSide,
    opacity: 0.3,
  });

  let lmesh = new THREE.Mesh(desci, [
    material2,
    material2,
    material2,
    material2,
    material,
    material,
  ]);
  let yIndex = reel.reelThickness / 2 + 1;
  yIndex = type == "front" ? yIndex : yIndex * -1;
  lmesh.position.set(item.x + item.length / 2, yIndex, item.y + item.width / 2);
  lmesh.rotation.set(-Math.PI / 2, 0, -(item.angle / 180) * Math.PI);
  mesh.add(lmesh);

  if (item.desiccantPlaceMethod == 1) {
    let dmesh = lmesh.clone();
    let dm = material.clone();
    dm.transparent = true;
    let dm2 = material2.clone();
    dm2.transparent = true;
    dmesh.material = [dm2, dm2, dm2, dm2, dm, dm];
    dmesh.position.set(
      item.x1 + item.length / 2,
      yIndex,
      item.y1 + item.width / 2
    );
    mesh.add(dmesh);
  }
}

function createCircleGeometry(item, type, label) {
  let r = (item.qaSize || 12) / 2;
  let qa = new THREE.CircleGeometry(r);
  let texture = loader.load(getAssetsFile("QA"));
  let material = new THREE.MeshBasicMaterial({
    map: texture,
    side: THREE.DoubleSide,
  });
  let lmesh = new THREE.Mesh(qa, material);
  // lmesh.position.set(item.qaStampx + r, item.qaStampy - item.width + r, 1);
  lmesh.position.set(
    item.qaStampX - item.length / 2 + r,
    -item.qaStampY + item.width / 2 - r,
    1
  );
  lmesh.rotation.set(0, 0, (item.qaStampAngle / 180) * Math.PI);
  label.add(lmesh);
}

init();

function action() {
  mesh.rotation.x += 0.001;
  mesh.rotation.y += 0.001;
  mesh.rotation.z += 0.001;
  render.render(scene, camera);
  frameId = requestAnimationFrame(action);
}

function resize() {
  render.setSize(can.value.offsetWidth, can.value.offsetHeight); // 根据缩放的窗口重新设置画布的大小
  // 垂直相机宽高比
  camera.aspect = can.value.offsetWidth / can.value.offsetHeight;
  // 更新相机投影矩阵
  camera.updateProjectionMatrix();
}
let debResize = debounce(resize, 100);

onMounted(() => {
  camera = new THREE.PerspectiveCamera(
    30,
    can.value.offsetWidth / can.value.offsetHeight,
    1,
    5000
  );
  camera.lookAt(0, 0, 0);
  camera.position.set(0, reel.reelDiameter * 3, 0);

  render = new THREE.WebGLRenderer({
    alpha: true,
    antialias: true,
  });
  render.setSize(can.value.offsetWidth, can.value.offsetHeight);
  render.setPixelRatio(window.devicePixelRatio);

  controls = new OrbitControls(camera, render.domElement);
  controls.addEventListener("change", () => {
    render.render(scene, camera);
  });
  can.value.appendChild(render.domElement);

  if (props.from == "home") {
    action();
  } else {
    render.render(scene, camera);
  }
  window.addEventListener("resize", debResize);
});

onBeforeUnmount(() => {
  if (props.from == "home") {
    frameId && cancelAnimationFrame(frameId);
  }
  window.removeEventListener("resize", debResize);
  scene.remove(mesh);
  render.dispose();
  controls = null;
  render = null;
  camera = null;
  scene = null;
});

watch(
  () => props.storeJson,
  () => {
    scene.remove(mesh);
    mesh.geometry.dispose();
    init();
    render.render(scene, camera);
  }
);
</script>
<style scoped lang="scss">
.td-box {
  width: 100%;
  height: 100%;
}
</style>
